#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>

using namespace std;

struct ThreadInfo
{
    pthread_t tid;
    string name;
};


static const int defalutnum = 5;

template<class T>
class ThreadPool
{
private:    //一些私有的关于锁的线程函数
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    } 

    void Unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void Wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void Wake()
    {
        pthread_cond_signal(&_cond);
    }

private:    
    bool IsQueueEmpty()
    {
        return _tasks.empty();
    }

    string GetThreadName(pthread_t tid)     //根据线程ID，获取线程名
    {
        for (aoto& info : _threads)
        {
            if (info.tid == tid)
            {
                return info.name;
            }
        }

        return "No such thread";    
    }

public:
    void start()   //启动线程池
    {
        int num = _threads.size();
        for (int i = 0; i < num; i++)
        {
            pthread_create(&_threads[i].tid, nullptr, HandlerTask, this);      //传this，让ThredHandldler函数变成静态(减少一个this参数)
            _threads[i].name = "Thread-" + to_string(i + 1);
        }
    }

    T Pop()
    {
        T t = _tasks.front();   //类型就是任务，取出队头任务
        _tasks.pop();
        return t;   
    }

    void Push(const T& t)
    {
        Lock();
        _tasks.push(t);
        Wake();     //（没有任务之后，进行wait）push之后就可以唤醒线程
        Unlock();
    }
    /*
    当等待队列有数据时（即有至少一个线程正在等待这个条件变量）：
    pthread_cond_signal 调用成功时，它会唤醒等待该条件变量的一个线程（在多个线程等待的情况下，具体唤醒哪一个线程取决于线程调度策略和实现）。
    返回值通常是 0，表示成功。

    当等待队列没有数据时（即没有线程正在等待这个条件变量）：
    pthread_cond_signal 调用仍然会成功执行，但是因为没有线程在等待，所以实际上没有线程被唤醒。
    返回值仍然是 0，表示成功。
    */

   static ThreadPool<T>* GetInstance()   //单例模式(一般静态成员会提供静态方法)
   {
        if (_instance == nullptr)       //防止重复加锁
        {
            pthread_mutex_lock(&_lock);
            if (_instance == nullptr)
            {
                std::cout << "log: singleton create done first!" << std::endl;
                _instance = new ThreadPool<T>();    //加锁申请
            }
            pthread_mutex_unlock(&_lock);
        }

        return _instance;
   }

private:    //默认成员函数
    ThreadPool()
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        _threads.resize(defalutnum);   //默认创建5个线程
    }

    ~ThreadPool()   
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        //全局锁和条件变量不需要销毁
        //STL自定义类型不用管
        // 内置类型不用管
    }  

    ThreadPool<T>& operator=(const ThreadPool<T>& t1) = delete;   //禁止拷贝构造
    
    ThreadPool(const ThreadPool<T>& t1) = delete;   //禁止拷贝构造



private: 
    vector<ThreadInfo> _threads;    //线程信息
    queue<T> _tasks;           //任务队列

    pthread_mutex_t _mutex;     //控制内部线程的互斥锁
    pthread_cond_t _cond;       //控制内部线程的条件变量

    static ThreadPool<T>* _instance;   //单例模式
    static pthread_mutex_t _lock;   //实例化单例时，进行保护的专门的锁
};


template<class T>   //使用模板时，需要点名模板，点名类域时，需要加上模板参数（模板实例化之后才是类）
ThreadPool<T>* ThreadPool<T>::_instance = nullptr;   //单例模式

template<class T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;   //实例化单例时，进行保护的专门的锁

